package com.heihei.itextdemo.util.dto;

import org.apache.commons.lang3.time.DateUtils;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;

/**
 * 线程安全的date工具类
 *
 * @author caichengzhe
 * @version 1.0
 * @company 洛阳图联科技有限公司
 * @copyright (c) 2017 LuoYang TuLian Co'Ltd Inc. All rights reserved.
 * @date 2018年3月12日 下午4:31:53
 * @since JDK1.8
 */
public class SmartDateUtil extends DateUtils {
    public static final int HOUR_MIN = 60;
    public static final long DAY_MI_SECOND = 24 * 60 * 60 * 1000;
    public static final Date EPOCH = new Date(0);
    private static final ThreadLocal<DateFormats> dateFormats = new ThreadLocal<DateFormats>() {
        protected DateFormats initialValue() {
            return new DateFormats();
        }
    };

    public static String formatYMD(Date date) {
        return dateFormats.get().ymd.format(date);
    }

    public static String curTime() {
        return dateFormats.get().ymdhms.format(new Date());
    }

    public static String formatYM(Date date) {
        return dateFormats.get().ym.format(date);
    }

    public static String formatHMS(Date date) {
        return dateFormats.get().hms.format(date);
    }

    public static String formatHM(Date date) {
        return dateFormats.get().hm.format(date);
    }

    public static String formatYMDHM(Date date) {
        return dateFormats.get().ymdhm.format(date);
    }

    public static String formatYMDHMS(Date date) {
        return dateFormats.get().ymdhms.format(date);
    }

    public static String formatYMDHMSSSS(Date date) {
        return dateFormats.get().ymdhmsSSS.format(date);
    }

    public static String formatYMDChinese(Date date) {
        return dateFormats.get().ymdChinese.format(date);
    }

    public static String formatYMDSlash(Date date) {
        return dateFormats.get().ymdSlash.format(date);
    }

    public static String formatYMDCount(Date date) {
        return dateFormats.get().ymdCount.format(date);
    }

    public static Date parseYMD(String dateStr) {
        return parse(dateFormats.get().ymd, dateStr);
    }

    public static Date parseYM(String dateStr) {
        return parse(dateFormats.get().ym, dateStr);
    }

    public static Date parseYMDHMS(String dateStr) {
        return parse(dateFormats.get().ymdhms, dateStr);
    }

    public static Date parseYMDHMSSSS(String dateStr) {
        return parse(dateFormats.get().ymdhmsSSS, dateStr);
    }

    public static Date parseTodayHMS(String dateStr) {
        String today = formatYMD(new Date());
        String todayDateStr = String.format("%s %s", today, dateStr);
        return parse(dateFormats.get().ymdhms, todayDateStr);
    }

    /**
     * 判断当前时间是否在某段时间内 参数不区分先后顺序
     */
    public static boolean isDuringTwoDate(Date date, Date another) {
        long dateTime = date.getTime();
        long anotherTime = another.getTime();
        long currentTime = System.currentTimeMillis();

        if (currentTime > dateTime && currentTime < anotherTime) {
            return true;
        } else if (currentTime > anotherTime && currentTime < dateTime) {
            return true;
        } else {
            return false;
        }
    }

    public static Date parse(SimpleDateFormat format, String dateStr) {
        try {
            Date d = format.parse(dateStr);
            Calendar c = Calendar.getInstance();
            c.setTime(d);
            int year = c.get(Calendar.YEAR);
            if (year >= 1000 && year <= 9999) {
                return d;
            } else {
                return null;
            }
        } catch (Exception ex) {
            return null;
        }
    }

    public static long daysOffsetWithoutWeekend(Date end, Date start) {
        end = parseYMD(formatYMD(end));
        start = parseYMD(formatYMD(start));
        return countDays(end, start) - countWeekend(end, start);
    }

    public static long daysOffset(Date date1, Date date2) {
        date1 = parseYMD(formatYMD(date1));
        date2 = parseYMD(formatYMD(date2));
        return (date1.getTime() - date2.getTime()) / DAY_MI_SECOND;
    }

    public static long duration(Date start, Date end) {
        if (end != null && start != null && end.getTime() >= start.getTime()) {
            return (end.getTime() - start.getTime()) / DAY_MI_SECOND + 1;
        }
        return 0;
    }

    /**
     * 方法描述  判断val是否在start和end范围内
     *
     * @param start 开始时间
     * @param end   结束时间
     * @param val   待比较时间
     * @return
     * @throws
     * @author caichengzhe
     * @date 2019年4月11日下午2:23:36
     */
    public static boolean include(Date start, Date end, Date val) {
        if (start == null || end == null || val == null) {
            return false;
        }
        return (val.getTime() >= start.getTime() && val.getTime() <= end.getTime());
    }

    public static long countWeekend(Date endDate, Date startDate) {
        Calendar start = Calendar.getInstance();
        start.setTime(startDate);
        long diff = daysOffset(endDate, startDate);
        long weekendCount = 0;
        while (diff >= 0) {
            int dayOfWeek = start.get(Calendar.DAY_OF_WEEK);
            if (Objects.equals(dayOfWeek, Calendar.SATURDAY) || Objects.equals(dayOfWeek, Calendar.SUNDAY)) {
                weekendCount++;
            }
            start.add(Calendar.DAY_OF_YEAR, 1);
            diff = daysOffset(endDate, start.getTime());
        }
        return weekendCount;
    }

    public static long countDays(Date endDate, Date startDate) {
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        start.setTime(startDate);
        end.setTime(endDate);
        long count = 0;
        while (getDiffDaysByCalendar(start, end) >= 0) {
            count++;
            start.add(Calendar.DAY_OF_YEAR, 1);
        }
        return count;
    }

    private static int getDiffDaysByCalendar(Calendar start, Calendar end) {
        return end.get(Calendar.DAY_OF_YEAR) - start.get(Calendar.DAY_OF_YEAR) + (end.get(Calendar.YEAR) - start.get(Calendar.YEAR)) * 365;
    }

    public static Date getBeginOfDay() {
        return getBeginOfDay(new Date());
    }

    public static Date getBeginOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public static Date getMidOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 12);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 1);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public static Date getEndOfDay() {
        return getEndOfDay(new Date());
    }

    public static Date getEndOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }

    public static Date getYestoday() {
        return addDays(new Date(), -1);
    }

    public static Date getTomorrow() {
        return addDays(new Date(), 1);
    }

    public static Date getBeginDayOfYear(String year) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, Integer.parseInt(year));
        cal.set(Calendar.MONTH, Calendar.JANUARY);
        cal.set(Calendar.DATE, 1);

        return getDayStartTime(cal.getTime());
    }

    public static Date getEndDayOfYear(String year) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, Integer.parseInt(year));
        cal.set(Calendar.MONTH, Calendar.DECEMBER);
        cal.set(Calendar.DATE, 31);
        return getDayEndTime(cal.getTime());
    }

    public static Date getDayStartTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Date(calendar.getTimeInMillis());
    }

    public static Date getDayEndTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Date(calendar.getTimeInMillis());
    }


}

class DateFormats {
    public final SimpleDateFormat hms = new SimpleDateFormat("HH:mm:ss");
    public final SimpleDateFormat hm = new SimpleDateFormat("HH:mm");
    public final SimpleDateFormat ymdhm = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    public final SimpleDateFormat ymd = new SimpleDateFormat("yyyy-MM-dd");
    public final SimpleDateFormat ym = new SimpleDateFormat("yyyy-MM");
    public final SimpleDateFormat ymdhms = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public final SimpleDateFormat ymdChinese = new SimpleDateFormat("yyyy年MM月dd");
    public final SimpleDateFormat ymdSlash = new SimpleDateFormat("yyyy/MM/dd");
    public final SimpleDateFormat ymdCount = new SimpleDateFormat("yyyyMMdd");
    public final SimpleDateFormat ymdhmsSSS = new SimpleDateFormat("yyyyMMddHHmmssSSS");
}
